package com.sky.aspect;

import com.aliyun.oss.common.utils.StringUtils;
import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Component
@Aspect
@Slf4j
public class AutoFillAspect {


    /**
     * 1. 多谢入点表达式的链接
     *  在切入点比表达式里：如果想要缩小Spring的扫描范围的话，可以使用多切入点表达式链接，连接符  $$
     *  选择要增强的方法：
     *      只扫描mapper层里的方法，并且 有@AutoFill注解的方法
     * 2. 带注解方式切入点的通知方法，如果想在通知方法里获取到对象可以写成：
     *     2.1 在方法上直接添加注解类型的形参
     *     2.2 修改切入点表达式
     *          原来：@annotation(注解的全限定类名)
     *          改成：@annotation(方法的注解类型形参)
     * @param joinPoint
     * @param
     */
    @Before("execution(* com.sky.mapper.*.*(..))  && @annotation(com.sky.annotation.AutoFill)")
//    public void autofill(JoinPoint joinPoint, AutoFill autoFill){
//        //获取目标方法的实参
//        Object[] args = joinPoint.getArgs();
//        //健壮性判断
//        if (args==null||args.length==0) {
//            return;
//        }
//        Object entity = args[0];
//        //准备要赋的值
//        LocalDateTime now = LocalDateTime.now();
//        Long currentUser = BaseContext.getCurrentId();
//        Class<?> clazz = entity.getClass();
//        if (autoFill.value()== OperationType.INSERT){
//            try {
//                //类型如果是插入，就设置四个值
//                Method setCreatTimeMethod = clazz.getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
//                Method setUpdateTime = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
//                Method setCreatUser = clazz.getDeclaredMethod(AutoFillConstant.SET_CREATE_USER,Long.class);
//                Method setUpdateUser = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//                setCreatTimeMethod.invoke(entity,now);
//                setUpdateTime.invoke(entity,now);
//                setCreatUser.invoke(entity, currentUser);
//                setUpdateUser.invoke(entity,currentUser);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//
//        }else {
//            try {
//                //类型如果是修改，就插入两个值
//                Method setUpdateTime = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
//                Method setUpdateUser = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
//                setUpdateTime.invoke(entity,now);
//                setUpdateUser.invoke(entity, currentUser);
//            } catch (Exception e) {
//                e.printStackTrace();
//            }
//        }
//    }

    public void autoFill(JoinPoint joinPoint){
        //1.获取方法参数 --实体对象
        Object[] args = joinPoint.getArgs();
        //2. 如果参数无值，拒绝处理
        if (args==null||args.length==0){
            log.error("参数无值，拒绝处理");
            return;
        }
        //3. 获取参数的实体对象
        Object entity = args[0];//实体对象

        //4. 获取目标方法的签名对象

        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        //5. 获取目标方法上的AutoFill注解对象
        AutoFill annotation = signature.getMethod().getAnnotation(AutoFill.class);

        //6. 获取注解对象里的value值
        OperationType operationType = annotation.value();
        //7. 操作类型是INSERt

        //准备赋值的数据
        LocalDateTime now = LocalDateTime.now();
        Long currentId = BaseContext.getCurrentId();
        //获取类的字节码文件
        Class<?> clazz = entity.getClass();
        if (operationType==OperationType.INSERT){
            try {
                //7.1 通过反射获取四个属性对应的方法对象
                Method setCreateTime = clazz.getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                Method setCreateUser = clazz.getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                Method setUpdateTime = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                //7.2 通过反射调用每个方法设置对应属性的值
                setCreateTime.invoke(entity,now);
                setCreateUser.invoke(entity,currentId);
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                e.printStackTrace();
                log.error("字段自动填充失败");
            }
        } else if(operationType==OperationType.UPDATE) {
            try {
                //8. 如果是UPDATE -自动填充两个字段的值

                //8.1 通过反射获取两个属性对应的方法对象
                Method setUpdateTime = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                Method setUpdateUser = clazz.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                //8.2 通过反射调用每个方法设置对应属性的值
                setUpdateTime.invoke(entity,now);
                setUpdateUser.invoke(entity,currentId);
            } catch (Exception e) {
                log.error("字段自动填充失败");
                e.printStackTrace();

             }
        }
    }
}
